package com.logic.modular.game.player.skill;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.comment.exception.ServiceException;
import com.logic.modular.game.player.bag.service.BagItemServiceImpl;
import com.logic.modular.game.player.bag.service.PlayerPropType2ServiceImpl;
import com.comment.pojo.domain.logic.domain.PlayerHero;
import com.comment.pojo.domain.logic.domain.PlayerSkill;
import com.logic.modular.game.player.skill.mapper.PlayerSkillMapper;
import com.comment.pojo.domain.logic.core.CoreAccountConfig;
import com.logic.modular.gameCore.config.mapper.CoreConfigMapper;
import com.comment.pojo.domain.logic.core.CoreSkill;
import com.comment.pojo.domain.logic.core.CoreSkillStar;
import com.logic.modular.gameCore.config.service.impl.CoreAccountConfigServiceImpl;
import com.logic.modular.gameCore.cultivate.skill.mapper.CoreSkillMapper;
import com.logic.modular.gameCore.cultivate.skill.mapper.CoreSkillStarMapper;
import com.logic.modular.gameCore.cultivate.skill.service.CoreSkillServiceImpl;
import com.logic.modular.gameCore.cultivate.skill.controller.CoreSkillStarServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 游戏账户技能数据(PlayerSkill)表服务实现类
 *
 * @author cxy
 * @since 2024-07-18 10:48:34
 */
@Slf4j
@Service
public class PlayerSkillServiceImpl extends PlayerSkillBaseServiceImpl {
    @Resource
    private PlayerSkillMapper accountSkillMapper;
    @Resource
    private CoreSkillStarServiceImpl coreSkillStarServiceImpl;
    @Resource
    private CoreSkillServiceImpl coreSkillServiceImpl;
    @Resource
    private BagItemServiceImpl bagItemService;
    @Resource
    private PlayerPropType2ServiceImpl playerPropType2ServiceImpl;
    @Resource
    private BagItemServiceImpl bagItemServiceImpl;
    @Autowired
    private CoreConfigMapper coreConfigMapper;
    @Autowired
    private CoreSkillMapper coreSkillMapper;
    @Autowired
    private CoreSkillStarMapper coreSkillStarMapper;

    @Transactional
    public void registerInit(Long playerId) {
        CoreAccountConfig coreAccountConfig = CoreAccountConfigServiceImpl.getCache(1L);
        // 物品信息
        Map<Long, Integer> skills = coreAccountConfig.getSkills();
        skills.forEach((coreSkillId,value) -> obtainSkill(playerId, coreSkillId));
    }


    /**
     * 获得技能 如果有转换成信物
     *
     * @param playerId
     * @param coreSkillId
     * @return
     */
    @Transactional
    public PlayerSkill obtainSkill(Long playerId, Long coreSkillId) {
        CoreSkill coreSkill = CoreSkillServiceImpl.getCache(coreSkillId);
        Integer talent = coreSkill.getTalent();
        if (talent == 1) {
            throw new ServiceException("该技能为天赋技能，无法获得");
        }

        LambdaQueryWrapper<PlayerSkill> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PlayerSkill::getUid, playerId);
        wrapper.eq(PlayerSkill::getCoreSkillId, coreSkillId);
        PlayerSkill one = getOne(wrapper);
        CoreSkillStar coreSkillStar = CoreSkillStarServiceImpl.getCache(coreSkill.getId(), 0);

        if (one == null) {
            PlayerSkill newPlayerSkill = PlayerSkill.builder()
                    .uid(playerId)
                    .coreSkillId(coreSkillId)
                    .coreSkillStarId(coreSkillStar.getId())
                    .star(coreSkillStar.getSkillStar())
                    .status(1)
                    .build();
            save(newPlayerSkill);
            return newPlayerSkill;
        }
        skillToProp(playerId, coreSkillId, 1);
        log.info("玩家{}技能{}已转化为信物", playerId, coreSkill.getId());
        return one;
    }

    /**
     * 获取技能
     *
     * @param playerId
     * @param coreSkillId
     * @return
     */
    public PlayerSkill obtainSkillNoTransformation(Long playerId, Long coreSkillId) {
        CoreSkill coreSkill = coreSkillMapper.selectById(coreSkillId);
        System.out.println(coreSkill);
        Integer talent = coreSkill.getTalent();
        if (talent == 1) {
            throw new ServiceException("该技能为天赋技能，无法获得");
        }

        LambdaQueryWrapper<PlayerSkill> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PlayerSkill::getUid, playerId);
        wrapper.eq(PlayerSkill::getCoreSkillId, coreSkillId);
        PlayerSkill one = getOne(wrapper);
        CoreSkillStar coreSkillStar = coreSkillStarMapper.selectOne(
                new LambdaQueryWrapper<CoreSkillStar>()
                        .eq(CoreSkillStar::getSkillId, coreSkillId)
                        .eq(CoreSkillStar::getSkillStar, 0)
        );

        if (one == null) {
            PlayerSkill newPlayerSkill = PlayerSkill.builder()
                    .uid(playerId)
                    .coreSkillId(coreSkillId)
                    .coreSkillStarId(coreSkillStar.getId())
                    .star(coreSkillStar.getSkillStar())
                    .status(1)
                    .build();
            save(newPlayerSkill);
            return newPlayerSkill;
        }
        return one;
    }

    private void skillToProp(
            Long playerId,
            Long coreSkillId,
            Integer quantity
    ) {
        Set<Long> propIds = coreSkillStarServiceImpl.getProp(coreSkillId).keySet();
        propIds.forEach(propId -> bagItemService.obtainBagItem(playerId, propId, BigDecimal.valueOf(quantity)));
    }


    public List<CoreSkillStar> list(PlayerHero playerHero) {
        return playerHero.getSkillStarIds().stream().map(coreSkillStarId ->
                coreSkillStarServiceImpl.getCache(coreSkillStarId)
        ).collect(Collectors.toList());
    }


    public PlayerSkill risingStar(Long playerId, Long playerSkillId) {
        PlayerSkill byId = getById(playerSkillId);
        int targetStar = byId.getStar() + 1;
        return risingStarToTargetStar(playerId, playerSkillId, targetStar);
    }

    /**
     * 技能升星到指定星
     *
     * @param playerId      玩家id
     * @param playerSkillId 玩家技能id
     * @param targetStar    目标星
     * @return 玩家技能
     */
    public PlayerSkill risingStarToTargetStar(
            Long playerId, Long playerSkillId, Integer targetStar
    ) {
        checkRisingMessage(playerId, playerSkillId, targetStar);
        boolean b = payRisingStarToTargetStarCost(playerId, playerSkillId, targetStar);
        if (b) {
            return risingStarToTargetStarHandle(playerId, playerSkillId, targetStar);
        } else {
            throw new ServiceException("当前技能未拥有升星材料不足");
        }
    }

    /**
     * 技能升星到指定星 不花钱升级
     */
    public PlayerSkill risingStarToTargetStarNoPay(
            Long playerId, Long playerSkillId, Integer targetStar
    ) {
        checkRisingMessage(playerId, playerSkillId, targetStar);
        return risingStarToTargetStarHandle(playerId, playerSkillId, targetStar);
    }

    private void checkRisingMessage(Long playerId, Long playerSkillId, Integer targetStar) {
        PlayerSkill byId = getById(playerSkillId);
        if (byId == null) {
            throw new ServiceException("当前技能不存在");
        }

        Integer star = byId.getStar();
        if (!byId.getUid().equals(playerId)) {
            throw new ServiceException("异常参数");
        }

        CoreSkill cache = CoreSkillServiceImpl.getCache(byId.getCoreSkillId());
        if (star >= cache.getQualityLv()) {
            throw new ServiceException("当前技能已满星", byId);
        }

        if (targetStar > cache.getQualityLv()) {
            throw new ServiceException("目标星阶大于当前技能最大星阶", targetStar);
        }
    }


    /**
     * 支付星阶消耗道具
     */
    public boolean payRisingStarToTargetStarCost(
            Long playerId, Long playerSkillId, Integer targetStar
    ) {
        PlayerSkill byId = getById(playerSkillId);
        // 计算需要支付的星阶
        int needPayStar = targetStar - byId.getStar();
        Map<Long, Integer> levelUpCost = new HashMap<>();
        for (int i = 0; i < needPayStar; i++) {
            long nextStarId = byId.getCoreSkillStarId() + 1;
            CoreSkillStar nextStar = coreSkillStarServiceImpl.getCache(nextStarId);
            Map<Long, Integer> thisUpNeed = nextStar.getLevelUpCost();
            thisUpNeed.forEach((k, v) -> {
                if (levelUpCost.containsKey(k)) {
                    levelUpCost.put(k, levelUpCost.get(k) + v);
                } else {
                    levelUpCost.put(k, v);
                }
            });
        }
        boolean isPay = false;
        Map<Long, Integer> rollback = new HashMap<>();
        for (Map.Entry<Long, Integer> entry : levelUpCost.entrySet()) {
            Long propId = entry.getKey();
            Integer propNum = entry.getValue();
            boolean b = playerPropType2ServiceImpl.tryPayProp(playerId, propId, BigDecimal.valueOf(propNum));
            if (!b) {
                rollback.forEach((k, v) -> bagItemServiceImpl.obtainBagItem(playerId, k, BigDecimal.valueOf(v)));
                isPay = false;
                break;
            } else {
                rollback.put(propId, propNum);
                isPay = true;
            }
        }
        return isPay;
    }


    public PlayerSkill risingStarToTargetStarHandle(
            Long playerId, Long playerSkillId, Integer targetStar
    ) {
        PlayerSkill byId = getById(playerSkillId);
        if (byId == null) {
            throw new ServiceException("当前技能不存在");
        }
        if (!byId.getUid().equals(playerId)) {
            throw new ServiceException("异常参数");
        }
        CoreSkill cache = CoreSkillServiceImpl.getCache(byId.getCoreSkillId());
        if (byId.getStar() >= cache.getQualityLv()) {
            throw new ServiceException("当前技能已满星", byId);
        }
        if (targetStar > cache.getQualityLv()) {
            throw new ServiceException("目标星阶大于当前技能最大星阶", targetStar);
        }

        LambdaQueryWrapper<CoreSkillStar> w = new LambdaQueryWrapper<>();
        w.eq(CoreSkillStar::getSkillId, byId.getCoreSkillId());
        w.eq(CoreSkillStar::getSkillStar, targetStar);
        CoreSkillStar nextStar = coreSkillStarServiceImpl.getOne(w);

        byId.setStar(nextStar.getSkillStar());
        byId.setCoreSkillStarId(nextStar.getId());
        updateById(byId);
        return byId;
    }
}
